package com.study.springCustom.spring.factory.support;

import com.study.springCustom.spring.ioc.BeanDefinition;
import com.study.springCustom.spring.ioc.PropertyValue;
import com.study.springCustom.spring.ioc.RuntimeBeanReference;
import com.study.springCustom.spring.ioc.TypedStringValue;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory{

    @Override
    protected Object createBean(BeanDefinition bd) {
        // 1、Bean的实例化（new对象）
        Object bean = createBeanInstance(bd);
        // 2、属性填充/依赖注入（setter）
        populateBean(bean,bd);
        // 3、Bean的初始化（调用初始化方法）
        initializingBean(bean,bd);
        return bean;
    }

    private void initializingBean(Object bean, BeanDefinition bd) {
        // TODO Aware接口的处理（在类创建成功之后，去通过Aware接口装饰一个类）
        // TODO BeanPostProcessor接口方法的处理
        // 处理初始化方法
        invokeInitMethod(bean,bd);
    }

    private void invokeInitMethod(Object bean, BeanDefinition bd) {
        // TODO InitializingBean接口的afterProertiesSet方法的处理
        // 调用自定义初始化方法
        try {
            String initMethod = bd.getInitMethod();
            if (initMethod == null || "".equals(initMethod)){
                return;
            }
            Class<?> clazzType = bd.getClazzType();
            Method method = clazzType.getDeclaredMethod(initMethod);
            method.invoke(bean);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 依赖注入
     * @param bean
     * @param bd
     */
    private void populateBean(Object bean, BeanDefinition bd) {
        List<PropertyValue> propertyValues = bd.getPropertyValues();
        for (PropertyValue pv : propertyValues) {
            String name = pv.getName();//属性名称
            Object value = pv.getValue();//需要处理的属性值
            Object valueToUse = resolveValue(value);// 处理属性值的
            setProperty(bean,name,valueToUse);
        }
    }

    private void setProperty(Object bean, String name, Object valueToUse) {
        try {
            Class<?> aClass = bean.getClass();
            Field field = aClass.getDeclaredField(name);
            field.setAccessible(true);
            field.set(bean,valueToUse);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private Object resolveValue(Object value) {
        Object valueToUse = null;
        if (value instanceof TypedStringValue){
            TypedStringValue typedStringValue = (TypedStringValue) value;

            Class<?> targetType = typedStringValue.getTargetType();
            String stringValue = typedStringValue.getValue();
            valueToUse = stringValue;
            if (targetType != null){
                valueToUse = handleType(targetType,stringValue);
            }
        }else if (value instanceof RuntimeBeanReference){
            RuntimeBeanReference beanReference = (RuntimeBeanReference) value;
            String ref = beanReference.getRef();
            // 注意：此处可能出现循环依赖问题
            valueToUse = getBean(ref);
        }
        return valueToUse;
    }

    private Object handleType(Class<?> targetType, String stringValue) {
        // TODO 后面是有设计模式进行优化
        if (targetType == Integer.class){
            return Integer.parseInt(stringValue);
        }else if (targetType == String.class){
            return stringValue;
        }//....
        return null;
    }

    private Object createBeanInstance(BeanDefinition bd) {
        // 通过实例工厂去创建Bean
        // 通过静态工厂去创建Bean
        try {
            Class<?> clazzType = bd.getClazzType();
            Constructor<?> constructor = clazzType.getDeclaredConstructor();
            return constructor.newInstance();
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

}
